// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: wsfuyibing <682805@qq.com>
// Date: 2024-12-11

package filter

import (
	"context"
	"fmt"
	"gitee.com/go-libs/log"
	"gitee.com/gomq/sr/errs"
	"strconv"
)

// This component used to match range operations.
type valueForRange struct {
	Err       error
	ErrExists bool
	Field     Field

	expect, expectRadix float64
	expectInt           int64
	query               string
}

// + Implemented

func (o *valueForRange) GetError() error                       { return o.Err }
func (o *valueForRange) GetField() Field                       { return o.Field }
func (o *valueForRange) HasError() bool                        { return o.ErrExists }
func (o *valueForRange) Match(ctx context.Context, v any) bool { return o.match(ctx, v) }
func (o *valueForRange) Query() string                         { return o.query }

// + Match

func (o *valueForRange) compare(ctx context.Context, got string) (yes bool) {
	var (
		err error
		f   float64
		i   int64
	)

	// Generate v as integer.
	if f, err = strconv.ParseFloat(got, 64); err == nil {
		i = int64(f * o.expectRadix)
		switch o.Field.GetOperator() {
		case OperatorGreater:
			yes = i > o.expectInt
		case OperatorGreaterEqual:
			yes = i >= o.expectInt
		case OperatorLess:
			yes = i < o.expectInt
		case OperatorLessEqual:
			yes = i <= o.expectInt
		default:
			err = fmt.Errorf(`unknown operator: %s`, o.Field.GetOperator())
		}
	}

	if err != nil {
		if log.Config().DebugOn() {
			log.Debugfc(ctx, `[filter][field=%s] skipped: error="%v"`, o.Field.GetKey(), err)
		}
		return false
	}
	if log.Config().DebugOn() {
		log.Debugfc(ctx, `[filter][field=%s] match result: success="%v", expression="%s %s"`, o.Field.GetKey(), yes, got, o.query)
	}
	return
}

func (o *valueForRange) match(ctx context.Context, v any) bool {
	return o.compare(ctx, fmt.Sprintf(`%v`, v))
}

// + Access

func (o *valueForRange) buildQuery() {
	o.query = fmt.Sprintf(`%s %v`,
		o.Field.GetOperator(),
		o.expect,
	)
}

func (o *valueForRange) init(str string) Value {
	o.expectRadix = 1000.0

	if o.parse(str); o.Err == nil {
		o.expectInt = int64(o.expect * o.expectRadix)
	} else {
		o.ErrExists = true
	}

	o.buildQuery()
	return o
}

func (o *valueForRange) parse(str string) {
	var (
		f   float64
		i   int64
		err error
	)

	if f, err = strconv.ParseFloat(str, 64); err == nil {
		o.expect = f
		return
	}

	if i, err = strconv.ParseInt(str, 10, 64); err == nil {
		o.expect = float64(i)
		return
	}

	o.Err = errs.ErrFilterInvalidNumberValue
}
